package protocol

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"gitee.com/hexug/devcloud/cmdb/apps"
	"gitee.com/hexug/devcloud/cmdb/common/logger"
	"gitee.com/hexug/devcloud/cmdb/conf"
	"gitee.com/hexug/devcloud/cmdb/swagger"
	restfulspec "github.com/emicklei/go-restful-openapi/v2"
	"github.com/emicklei/go-restful/v3"
)

func NewHTTPService() *HTTPService {
	r := restful.DefaultContainer
	// 跨域中间件
	cors := restful.CrossOriginResourceSharing{
		AllowedHeaders: []string{"*"},
		AllowedDomains: []string{"*"},
		AllowedMethods: []string{"HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE"},
		CookiesAllowed: false,
		Container:      r,
	}
	// 将跨域中间件装载到容器中
	r.Filter(cors.Filter)
	// r.Filter(svcauth.NewServerAuth().HttpAuth)
	server := &http.Server{
		ReadHeaderTimeout: 60 * time.Second,
		ReadTimeout:       60 * time.Second,
		WriteTimeout:      60 * time.Second,
		IdleTimeout:       60 * time.Second,
		MaxHeaderBytes:    1 << 20, // 1M
		Addr:              fmt.Sprintf("%s:%d", conf.C().Http.Host, conf.C().Http.Port),
		Handler:           r,
	}

	return &HTTPService{
		Container: r,
		server:    server,
	}
}

// HTTPService http服务
type HTTPService struct {
	Container *restful.Container
	server    *http.Server
}

// mcenter/api/tokens/v1
// mcenter/api/users/v1
func (s *HTTPService) PathPrefix() string {
	return fmt.Sprintf("/%s/api", "mcenter")
}

// Start 启动服务
func (s *HTTPService) Start() error {
	//初始化挂载路由
	apps.InitHttp(s.PathPrefix(), s.Container)
	// 装置子服务路由
	//配置API的swagger文档
	config := restfulspec.Config{
		// api列表是根据这个restful WebServices列表构建的。
		WebServices: restful.RegisteredWebServices(), //可以控制哪些服务是可见的
		//配置产生swagger文档的路径
		APIPath: "/apidocs.json",
		//[可选]如果设置，则使用生成的Swagger对象调用此函数
		PostBuildSwaggerObjectHandler: swagger.Docs,
		//指定根据name处理  这里处理state sizeCache  unknownFields三个name，这三个name是proto中字段，不是有效字段，需要忽略掉
		DefinitionNameHandler: func(name string) string {
			if name == "state" || name == "sizeCache" || name == "unknownFields" {
				return ""
			}
			return name
		},
	}
	//将swagger相关的配置装载到容器中
	//注意，所有路由的加载一定是要在装载swagger配置之前
	s.Container.Add(restfulspec.NewOpenAPIService(config))
	logger.L().Infof("Get the API using http://%s:%d%s", conf.C().Http.Host, conf.C().Http.Port, config.APIPath)

	// 启动 HTTP服务
	logger.L().Infof("HTTP服务启动成功, 监听地址: %s", s.server.Addr)
	if err := s.server.ListenAndServe(); err != nil {
		if err == http.ErrServerClosed {
			logger.L().Infof("服务已经停止了")
		}
		return fmt.Errorf("启动服务出错, %s", err.Error())
	}
	return nil
}

// Stop 停止server
func (s *HTTPService) Stop() error {
	logger.L().Info("开始关闭HTTP服务")
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	ch := make(chan struct{}, 1)
	var (
		err error
	)
	go func(ct context.Context, workDone chan struct{}) {
		err = s.server.Shutdown(ctx)
		workDone <- struct{}{}
	}(ctx, ch)
	select { //下面的case只执行最早到来的那一个
	case <-ch:
		if err != nil {
			return err
		}
		return nil
	case <-ctx.Done():
		logger.L().Error("HTTP关闭服务超时, 强制退出")
		return nil
	}
}
